package com.bayleaf.web.standardNameChecker;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

import com.bayleaf.core.BayleafServlet;
import com.bayleaf.core.Model;
import com.bayleaf.dao.BayleafDictionaryDAO;
import com.bayleaf.domain.DictionaryVO;


@WebServlet(name="standardNameChecker",
        urlPatterns={"/standardNameChecker"},
        initParams={ @WebInitParam(name="title", value="Standard Name Checker"), @WebInitParam(name="jsp", value="/standardNameChecker/StandardNameChecker") } )
public class StandardNameCheckerServlet extends BayleafServlet {
	
    @Override
    public String process(Model model) throws Exception{
    	BayleafDictionaryDAO dao = new BayleafDictionaryDAO();
    	List<DictionaryVO> dataList = dao.getStdNameListByNm("", "");
    	
    	List<StandardToken> data = getTokens(model.getString("input"));
    	
    	for(StandardToken token : data){
    		checkStandard(token,dataList);
    	}
    	
    	model.setObject("output", data.toArray());
    	
        return null;
    }

    /**
     * 줄별토큰을 나누어 가져온다(underscore방식)
     * @param raw
     * @return
     */
    private List<StandardToken> getTokens(String inData){
    	String[] rows = inData.split("\r\n");
    	String[] tokens; 
    	List<StandardToken> resultList = new ArrayList<StandardToken>();
    	for(int i = 0 ; i < rows.length ; i++){
    		tokens = rows[i].split("_");
    		for(int j = 0 ; j < tokens.length ; j++){
    			if(j+1 == tokens.length) {
    				resultList.add(new StandardToken(tokens[j], "\r\n"));
    				break;
    			}
    			resultList.add(new StandardToken(tokens[j], "_"));
    		}
    	}
    	return resultList;
    }
     
    /**
     * 표준을 확인하여 추천단어를 리스팅한다
     * @param token
     * @param standardList
     */
    private void checkStandard(StandardToken token, List<DictionaryVO> standardList ){
    	String name = token.getToken();
    	for(DictionaryVO vo : standardList){
    		if(vo.getStdNameEng().equals(name)){
    			token.setWrongStandard(false);
    			return;
    		}else{
    			//같지 않을경우 차이를 계속 계산
    			vo.setDistance(getLevenshteinDistance(name,vo.getStdNameEng()));
    		}
    	}
    	//차이별로 소팅
    	Collections.sort(standardList);
    	List<String> recommendList = new ArrayList<String>(); 
    	//추천 리스트에 담음 (distance 수치 조절로 strict 수위를 조절할 수 있음)
    	for (int i = 0; i < standardList.size(); i++) {
    		if(standardList.get(i).getDistance()<=5)
    			recommendList.add(standardList.get(i).getStdNameEng());
    		if(recommendList.size() >5) break;
		}
    	
    	token.setRecommendList(recommendList.toArray(new String[recommendList.size()]));
    }
    
    /**
     * 추천단어 검색 알고리즘 
     * 
     * getLevenshteinDistance(null, *)             = IllegalArgumentException
     * getLevenshteinDistance(*, null)             = IllegalArgumentException
     * getLevenshteinDistance("","")               = 0
     * getLevenshteinDistance("","a")              = 1
     * getLevenshteinDistance("aaapppp", "")       = 7
     * getLevenshteinDistance("frog", "fog")       = 1
     * getLevenshteinDistance("fly", "ant")        = 3
     * getLevenshteinDistance("elephant", "hippo") = 7
     * getLevenshteinDistance("hippo", "elephant") = 7
     * getLevenshteinDistance("hippo", "zzzzzzzz") = 8
     * getLevenshteinDistance("hello", "hallo")    = 1
     *
     * @param s  the first String, must not be null
     * @param t  the second String, must not be null
     * @return result distance
     * @throws IllegalArgumentException if either String input <code>null</code>
     */
    private int getLevenshteinDistance(String s, String t) {
        if (s == null || t == null) {
            throw new IllegalArgumentException("Strings must not be null");
        }
        s = s.toUpperCase();
        t = t.toUpperCase();

        int n = s.length(); // length of s
        int m = t.length(); // length of t

        if (n == 0) {
            return m;
        } else if (m == 0) {
            return n;
        }

        if (n > m) {
            // swap the input strings to consume less memory
            String tmp = s;
            s = t;
            t = tmp;
            n = m;
            m = t.length();
        }

        int p[] = new int[n+1]; //'previous' cost array, horizontally
        int d[] = new int[n+1]; // cost array, horizontally
        int _d[]; //placeholder to assist in swapping p and d

        // indexes into strings s and t
        int i; // iterates through s
        int j; // iterates through t

        char t_j; // jth character of t

        int cost; // cost

        for (i = 0; i<=n; i++) {
            p[i] = i;
        }

        for (j = 1; j<=m; j++) {
            t_j = t.charAt(j-1);
            d[0] = j;

            for (i=1; i<=n; i++) {
                cost = s.charAt(i-1)==t_j ? 0 : 1;
                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
                d[i] = Math.min(Math.min(d[i-1]+1, p[i]+1),  p[i-1]+cost);
            }

            // copy current distance counts to 'previous row' distance counts
            _d = p;
            p = d;
            d = _d;
        }

        // our last action in the above loop was to switch d and p, so p now 
        // actually has the most recent cost counts
        return p[n];
    }




}
